// go get go.uber.org/zap
// go get gopkg.in/natefinch/lumberjack.v2
package loggerv

import (
	"fmt"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
	"os"
	"path/filepath"
	"sync"
	"time"
)

var (
	Logger                      *zap.Logger
	deviceLoggers               sync.Map
	deviceConsole               bool
	mu                          sync.Mutex
	basePath                    = "logs"
	maxSize, maxBackups, maxAge = 1024, 3, 1000
	pre                         = "vtool"
)

func init() {
	updateLoggers()
	setupMidnightLoggerRotation()
}
func Config(MaxSize, MaxBackups, MaxAge int, BasePath, Pre string, DeviceConsole bool) {
	maxSize = MaxSize
	maxBackups = MaxBackups
	maxAge = MaxAge
	basePath = BasePath
	pre = Pre
	deviceConsole = DeviceConsole
}

func updateLoggers() {
	mu.Lock()
	defer mu.Unlock()
	today := time.Now().Format("2006-01-02") //TODO
	//today := time.Now().Format("2006-01-02T1504")
	Logger = newLogger(filepath.Join(basePath, today, pre+".log"), true)
	deviceLoggers.Range(func(key, value interface{}) bool {
		deviceID := key.(string)
		deviceLoggers.Store(deviceID, newLogger(filepath.Join(basePath, today, pre+"_"+deviceID+".log"), true))
		return true
	})
}

func newLogger(filename string, consoleOutput bool) *zap.Logger {
	writer := zapcore.AddSync(&lumberjack.Logger{
		Filename:   filename,
		MaxSize:    maxSize, // MB
		MaxBackups: maxBackups,
		MaxAge:     maxAge, // days
		Compress:   true,
	})

	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	core := zapcore.NewCore(zapcore.NewJSONEncoder(encoderConfig), writer, zap.InfoLevel)

	if consoleOutput {
		consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
		consoleCore := zapcore.NewCore(consoleEncoder, zapcore.AddSync(zapcore.Lock(os.Stdout)), zap.InfoLevel)
		core = zapcore.NewTee(core, consoleCore)
	}
	return zap.New(core)
}

func GetLogger() *zap.Logger {
	return Logger
}

func GetDeviceLogger(deviceID string) *zap.Logger {
	if log, ok := deviceLoggers.Load(deviceID); ok {
		return log.(*zap.Logger)
	}

	mu.Lock()
	defer mu.Unlock()
	newLog := newLogger(filepath.Join(basePath, time.Now().Format("2006-01-02"), pre+"_"+deviceID+".log"), deviceConsole) //TODO
	//newLog := newLogger(filepath.Join(basePath, time.Now().Format("2006-01-02T1504"), pre+"_"+deviceID+".log"), deviceConsole)
	deviceLoggers.Store(deviceID, newLog)
	return newLog
}

func setupMidnightLoggerRotation() {
	go func() {
		for {
			now := time.Now()
			next := now.Add(time.Hour * 24)                                                      //TODO
			next = time.Date(next.Year(), next.Month(), next.Day(), 0, 0, 0, 0, next.Location()) //TODO
			//next := now.Add(time.Minute * 1)
			//next = time.Date(next.Year(), next.Month(), next.Day(), next.Hour(), next.Minute(), 0, 0, next.Location())
			until := time.Until(next)
			fmt.Println("utils: ", until)
			time.Sleep(until)
			updateLoggers()
		}
	}()
}
